
#include "exception.h"
#include "eval.h"

#include <boost/tokenizer.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>


using namespace awa;

#define ARG(z, n, data)     data.args[n]

#define EXECFN(z, n, data)     \
  case n : return (*(static_cast<BOOST_PP_CAT(boost::function, n)<Generic BOOST_PP_COMMA_IF(n) ENUM(n, Generic)>* >(data.fn)))(BOOST_PP_ENUM(n, ARG, data)); \
  break;

#define CALLFN(fnImpl)         BOOST_PP_REPEAT(MAX_ARG, EXECFN, fnImpl)

#define NAMEDELIMITER     ":"
#define OBJECTDELIMITER   "."

namespace awa {  
  typedef boost::char_separator<Interface::value_type> Grammar;

typedef boost::tokenizer< Grammar >                  Tokenizer;
};

using namespace awa;

Interface ReadNode(const AbstractTree::tree_type& node) {

  Interface tags(node.get()->nodename);
  for(int i = 0; i < node.size()-1;i++)
    if(node[i].get()->type == XercesDOMNode::value_type::ATTRIBUTE_NODE)
      tags += "|" + node[i].get()->nodename;
  return tags;
}

Interface getNamespace(AbstractTree::tree_type& element) {

  Interface tags( ReadNode(element) );

  Tokenizer tokens(tags, awa::Grammar( NAMEDELIMITER ));
  assert( tokens.begin() != tokens.end() );
  return *tokens.begin();
}

Interface getObject(AbstractTree::tree_type& element) {

  Interface tags( ReadNode(element) );

  Tokenizer tokens( tags, awa::Grammar(OBJECTDELIMITER));
  assert( tokens.begin() != tokens.end() );
  
  Tokenizer::value_type tmp(*tokens.begin());
  return tmp.erase(0, getNamespace(element).length());
}

Interface getFunction(AbstractTree::tree_type& element) {

  Interface Interfaces( ReadNode(element) );
  
  return Interfaces.erase(0, (getNamespace(element).length() + getObject(element).length() + 1));
}


std::pair<Signature, Impl> resolv(AbstractTree::tree_type& element) {
  
  if(MainEntry.first.size() == 1)
    if(getObject(element) == "Main")
      return MainEntry;
}

std::pair<Signature, Impl> resolv( Generic& node ) {

  AbstractTree::tree_type element(castTo<AbstractTree::tree_type>(node));

  std::vector<Signature> MatchFnName;
  Interface signature[] = { getNamespace( element ), getObject( element ), getFunction(element) };

  if(!(signature[0].length() && signature[1].length() && signature[2].length()))
    throw RuntimeException("Incomplete Function Signature");
  
  TypeCollection::iterator itrType;
  ObjectCollection::iterator itrObj;
  if((itrType = NativeTypes.find(signature[0])) != NativeTypes.end())
    if((itrObj = itrType->second.find(signature[1])) != itrType->second.end()) 
      for(ImplCollection::iterator i = itrObj->second.begin();i != itrObj->second.end(); i++)
	if(*(i->first.begin()) == signature[2] && ((i->first.size() - 1) != element.size()) )
	  MatchFnName.insert( MatchFnName.end(), Signature(i->first.begin(), i->first.end()) );
  
  if(!MatchFnName.size())
    throw RuntimeException( ("No Match For Function " + signature[0] + "::" + signature[1] + "." + signature[2]).c_str() );
  else
    if(MatchFnName.size() > 1)
      for(std::vector<Signature>::iterator i = MatchFnName.begin(); i != MatchFnName.end(); i++)
	{
	  Signature::iterator fnname = i->begin();
	  for(AbstractTree::level_order_iterator j = element.level_order_begin(); j != element.level_order_end(); j++)
	    if(j->type == XercesDOMNode::value_type::ATTRIBUTE_NODE)
	      if(*(++fnname) != j->nodename)
		{
		  MatchFnName.erase( i );
		  break;
		}
	}
  if(!MatchFnName.size())
    throw RuntimeException( ("No Match For Function " + signature[0] + "::" + signature[1] + "." + signature[2]).c_str() );
  else
    if(MatchFnName.size() > 1)
      throw RuntimeException( ("Multiple Matches For Function " + signature[0] + "::" + signature[1] + "." + signature[2]).c_str() );

  std::list<Interface> tmp(MatchFnName.begin()->begin(), MatchFnName.begin()->end());
  return *(NativeTypes.find(signature[0])->second.find(signature[1])->second.find(tmp));
}

Generic exec( const Impl& i) {  
  switch(i.args.size()) {
        CALLFN(i)
    }
}

Generic exec(AwaAbstract* o, const Impl& i) {
  return o->EXEC( i );

}


Generic awa::eval( AbstractTree::tree_type& node)  { // For Main

  Impl fnBody;
  try {
    fnBody = resolv( node ).second;
  }catch(RuntimeException& e) {
    throw;
  } 
  
  fnBody.args.insert(fnBody.args.end(), Generic(node));
  return exec(fnBody);
}


Generic awa::eval( const Generic& tree ) {
  
  AbstractTree::tree_type node(castTo<AbstractTree::tree_type>(tree));
  
  Impl fnBody;
  try {
    fnBody = resolv( node ).second;
  }catch(RuntimeException& e) {
    throw;
  } 
  
  AbstractTree::level_order_node_iterator i = node.node_begin()->level_order_node_begin();
  for(; i != node.node_begin()->level_order_node_end();i++)
    fnBody.args.insert(fnBody.args.end(), eval(Generic(*i)));
  
  if( getNamespace(node) == "FUNCTION")
    return exec(fnBody);
  
  AwaAbstract* AwaInterface = castTo<AwaAbstract*>(&fnBody.args[0]);
  fnBody.args.erase( fnBody.args.begin() );
  return exec(AwaInterface, fnBody);
  
}
  

